package com.thlws.java.jdk8.methodReference;

import com.thlws.java.jdk8.methodReference.entity.*;

import java.time.LocalDate;
import java.util.*;

/**
 *
 * 方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行
 * 方法的方式，它需要由兼容的函数式接口构成的目标类型上下文。计算时，方法引用会创建函数式接口的一个实例。
 * 方法引用是一个Lambda表达式，其中方法引用的操作符是双冒号"::"
 *
 * 四种方法引用类型
 * 引用静态方法	ContainingClass::staticMethodName
 * 引用某个类型的任意对象的实例方法	ContainingType::methodName
 * 引用构造方法	ClassName::new
 *  示例：String::new， 等价于lambda表达式 () -> new String()
 *
 * 引用某个对象的实例方法	containingObject::instanceMethodName(分三种)
 *  1.实例上的实例方法引用
 *  instanceReference::methodName
 *
 *  2.超类上的实例方法引用
 *  super::methodName
 *
 *  3.类型上的实例方法引用
 *  ClassName::methodName
 *  实例方法要通过对象来调用，方法引用对应Lambda，Lambda的第一个参数会成为调用实例方法的对象。
 *  如下示例
 *  String::toString 等价于lambda表达式 (s) -> s.toString() ,其中s就是调用实例方法toString的对象
 *  String::compareToIgnoreCase 等价于 (s1,s2)->s1.compareToIgnoreCase(s2), s1就是调用实例方法compareToIgnoreCase的对象
 *
 * @author HanleyTang
 * @date 2018/11/21
 */
public class MethodReferenceDemo {

    public static void main(String[] args) {
        MethodReferenceDemo demo = new MethodReferenceDemo();
        demo.methodRef5();
    }


    /***
     * 数组排序，类型上的实例方法引用
     */
    public void methodRef1(){
        String [] stringArray = new String[]{"tang","wu","han"};

        //最原始的接口内部类实现机制
        Arrays.sort(stringArray,new Comparator<String>(){

            @Override
            public int compare(String s1, String s2) {
                return  s1.compareToIgnoreCase(s2);
            }
        });



        //lambda1, s1.compareToIgnoreCase(s2);  就是实现了 Comparator.compare方法
        Arrays.sort(stringArray,(s1,s2) -> {
            return s1.compareToIgnoreCase(s2);
        });
        //lambda2
        Arrays.sort(stringArray,(s1,s2)->s1.compareToIgnoreCase(s2));

        //类型上的实例方法引用，无需写参数,只需要 ClassName:methodName 系统会自动带入所需参数
        //methodName中 Arrays.sort(p1,p2)中p2参数 实际上是函数式接口,p2对应函数式接口中的方法 Comparator.compare(s1,s2)
        //String::compareToIgnoreCase 实际上就是 Comparator.compare 的实现，自动调用 s1.compareToIgnoreCase(s2) 而已
        //String::compareToIgnoreCase 会接收到 Comparator.compare(s1,s2) 中的两个参数,并自动调用 s1.compareToIgnoreCase(s2)
        //String::compareToIgnoreCase 就是方法引用，本质上就是一个lambda表达式
        //注意 String.compareToIgnoreCase并不是 static 修饰的,他属于 类型上的实例方法引用
        //String::compareToIgnoreCase 等价于 (s1,s2)->s1.compareToIgnoreCase(s2), s1就是调用实例方法compareToIgnoreCase的对象
        Arrays.sort(stringArray,String::compareToIgnoreCase);

    }


    /**
     * 静态方法引用
     */
    public void methodRef2(){
        Person[] pArr = new Person[]{
                new Person("003", LocalDate.of(2016,9,1)),
                new Person("001", LocalDate.of(2016,2,1)),
                new Person("002", LocalDate.of(2016,3,1)),
                new Person("004", LocalDate.of(2016,12,1))};

        // 使用匿名类
        Arrays.sort(pArr, new Comparator<Person>() {
            @Override
            public int compare(Person a, Person b) {
                return a.getBirthday().compareTo(b.getBirthday());
            }
        });


        //使用lambda表达式
        Arrays.sort(pArr, (Person a, Person b) -> {
            return a.getBirthday().compareTo(b.getBirthday());
        });


        //使用lambda表达式和类的静态方法
        Arrays.sort(pArr, (a ,b) -> Person.compareByAge(a, b));


        //使用方法引用，引用的是类的静态方法
        Arrays.sort(pArr, Person::compareByAge);

    }


    /***
     * 找集合中 max num,静态方法引用
     */
    public void methodRef3(){

        ArrayList<Num> a1 = new ArrayList<Num>();
        a1.add(new Num(1));
        a1.add(new Num(4));
        a1.add(new Num(2));
        a1.add(new Num(9));
        a1.add(new Num(3));
        a1.add(new Num(7));


        //相当于实现了  Comparator.compare(o1,o2)函数式接口
        Num num = Collections.max(a1, MethodReferenceDemo::compareNum);

        System.out.println("max num  = " + num.getVal());
    }



    /**
     * 字符串反转,实例方法引用
     */
    public void methodRef4(){
        String str = "i am hanley tang,my email is hanley@thlws.com";
        MyStrImpl impl = new MyStrImpl();
        String result = strOps(impl::strReverse, str);
        System.out.println("result = " + result);
    }


    /***
     * 构造器引用
     * 注意：构造器引用针对的也是 函数式接口
     */
    public void methodRef5(){
        MyFunc myFunc = MyClass::new;
        MyClass myClass = myFunc.func("Hanley Tang");
        System.out.println("myClass = " + myClass.getVal());
    }


    public static int compareNum(Num n1, Num n2) {
        return n1.getVal() - n2.getVal();
    }

    public  String strOps(MyStrFunc func, String val) {
        return func.func(val);
    }

}
